Add support for non-transitive dependencies
authorYehuda Katz + Carl Lerche <engineering@tilde.io>
Wed, 2 Jul 2014 23:32:24 +0000 (16:32 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 3 Jul 2014 14:30:11 +0000 (07:30 -0700)
Development and test dependencies should not be transitively pulled in.
For example, if I use rust-curl, and it happens to use hamcrest for
testing, that does not mean I depend on hamcrest.

src/cargo/core/dependency.rs
src/cargo/core/resolver.rs

index 6e4c8b25ff8f415845f9171ee7115f2eb018ba0c..a96e895610c4aa619d333606c007bd8e7736cf07 100644 (file)
@@ -5,7 +5,8 @@ use util::CargoResult;
 pub struct Dependency {
     name: String,
     namespace: SourceId,
-    req: VersionReq
+    req: VersionReq,
+    transitive: bool
 }
 
 impl Dependency {
@@ -20,7 +21,8 @@ impl Dependency {
         Ok(Dependency {
             name: name.to_str(),
             namespace: namespace.clone(),
-            req: version
+            req: version,
+            transitive: true
         })
     }
 
@@ -35,6 +37,16 @@ impl Dependency {
     pub fn get_namespace<'a>(&'a self) -> &'a SourceId {
         &self.namespace
     }
+
+    pub fn as_dev(&self) -> Dependency {
+        let mut dep = self.clone();
+        dep.transitive = false;
+        dep
+    }
+
+    pub fn is_transitive(&self) -> bool {
+      self.transitive
+    }
 }
 
 #[deriving(PartialEq,Clone,Encodable)]
index 2f07aaf749314e036066ad1b991666a1c1fd6dc4..ee51c96805a20444c655849a301926d364d64df0 100644 (file)
@@ -47,6 +47,8 @@ pub fn resolve<R: Registry>(deps: &[Dependency],
         resolve.insert(pkg.get_name().to_str(), pkg.clone());
 
         for dep in pkg.get_dependencies().iter() {
+            if !dep.is_transitive() { continue; }
+
             if !resolve.contains_key_equiv(&dep.get_name()) {
                 remaining.push(dep.clone());
             }
@@ -63,18 +65,31 @@ mod test {
     use core::{Dependency, PackageId, Summary};
     use super::resolve;
 
-    macro_rules! pkg(
-        ($name:expr => $($deps:expr),+) => (
-            {
+    trait ToDep {
+        fn to_dep(self) -> Dependency;
+    }
+
+    impl ToDep for &'static str {
+        fn to_dep(self) -> Dependency {
             let url = url::from_str("http://example.com").unwrap();
             let source_id = SourceId::new(RegistryKind, Remote(url));
-            let d: Vec<Dependency> = vec!($($deps),+).iter().map(|s| {
-                Dependency::parse(*s, Some("1.0.0"), &source_id).unwrap()
-            }).collect();
+            Dependency::parse(self, Some("1.0.0"), &source_id).unwrap()
+        }
+    }
+
+    impl ToDep for Dependency {
+        fn to_dep(self) -> Dependency {
+            self
+        }
+    }
+
+    macro_rules! pkg(
+        ($name:expr => $($deps:expr),+) => ({
+            let d: Vec<Dependency> = vec!($($deps.to_dep()),+);
+
             Summary::new(&PackageId::new($name, "1.0.0", &registry_loc()).unwrap(),
                          d.as_slice())
-            }
-        );
+        });
 
         ($name:expr) => (
             Summary::new(&PackageId::new($name, "1.0.0", &registry_loc()).unwrap(),
@@ -153,4 +168,18 @@ mod test {
 
         assert_that(&res, contains(names(["foo", "bar"])));
     }
+
+    #[test]
+    pub fn test_resolving_with_dev_deps() {
+        let mut reg = registry(vec!(
+            pkg!("foo" => "bar", dep("baz").as_dev()),
+            pkg!("baz" => "bat", dep("bam").as_dev()),
+            pkg!("bar"),
+            pkg!("bat")
+        ));
+
+        let res = resolve([dep("foo"), dep("baz").as_dev()], &mut reg).unwrap();
+
+        assert_that(&res, contains(names(["foo", "bar", "baz"])));
+    }
 }